```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Spring MVC文件上传下载最佳实践</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Hiragino Sans GB", Simsun, sans-serif;
            line-height: 1.8;
            color: #333;
            background-color: #f9f9f9;
        }
        h1, h2, h3, h4, h5, h6 {
            font-family: 'Noto Serif SC', serif;
            font-weight: 600;
        }
        .hero {
            background: linear-gradient(135deg, #6e8efb, #a777e3);
            color: white;
        }
        .card {
            transition: transform 0.3s ease, box-shadow 0.3s ease;
            border-radius: 12px;
            overflow: hidden;
        }
        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
        }
        .code-block {
            font-family: 'Courier New', Courier, monospace;
            background-color: #282c34;
            color: #abb2bf;
            border-radius: 8px;
            position: relative;
        }
        .code-header {
            background-color: #21252b;
            padding: 8px 12px;
            color: #9da5b3;
            font-size: 0.9em;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .code-copy {
            cursor: pointer;
            transition: color 0.2s;
        }
        .code-copy:hover {
            color: #61afef;
        }
        .tip-box {
            border-left: 4px solid #4fd1c5;
            background-color: #f0fdfa;
        }
        .warning-box {
            border-left: 4px solid #f6ad55;
            background-color: #fff7ed;
        }
        .danger-box {
            border-left: 4px solid #f56565;
            background-color: #fef2f2;
        }
        .hover-grow {
            transition: transform 0.2s;
        }
        .hover-grow:hover {
            transform: scale(1.02);
        }
        .code-tab {
            display: inline-block;
            padding: 8px 16px;
            cursor: pointer;
            border-radius: 6px 6px 0 0;
            background-color: #e2e8f0;
            margin-right: 4px;
        }
        .code-tab.active {
            background-color: #282c34;
            color: white;
        }
    </style>
</head>
<body class="antialiased">
    <!-- Hero Section -->
    <section class="hero py-20 px-4 md:px-0">
        <div class="container mx-auto max-w-5xl">
            <div class="flex flex-col md:flex-row items-center">
                <div class="md:w-3/5 mb-10 md:mb-0">
                    <h1 class="text-4xl md:text-5xl font-bold leading-tight mb-4">Spring MVC文件上传下载</h1>
                    <p class="text-xl md:text-2xl opacity-90 mb-8">高效与安全的最佳实践指南</p>
                    <div class="flex flex-wrap gap-3">
                        <span class="bg-white bg-opacity-20 px-4 py-2 rounded-full text-sm">文件上传</span>
                        <span class="bg-white bg-opacity-20 px-4 py-2 rounded-full text-sm">文件下载</span>
                        <span class="bg-white bg-opacity-20 px-4 py-2 rounded-full text-sm">安全最佳实践</span>
                        <span class="bg-white bg-opacity-20 px-4 py-2 rounded-full text-sm">性能优化</span>
                    </div>
                </div>
                <div class="md:w-2/5">
                    <div class="bg-white bg-opacity-20 p-8 rounded-xl backdrop-blur-sm">
                        <i class="fas fa-file-upload text-5xl mb-6 opacity-90"></i>
                        <h3 class="text-xl font-semibold mb-3">关键要点</h3>
                        <ul class="space-y-2">
                            <li class="flex items-start">
                                <i class="fas fa-check-circle mt-1 mr-2 text-green-200"></i>
                                <span>配置MultipartResolver处理上传</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle mt-1 mr-2 text-green-200"></i>
                                <span>设置文件大小和类型限制</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle mt-1 mr-2 text-green-200"></i>
                                <span>安全的文件存储和访问控制</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle mt-1 mr-2 text-green-200"></i>
                                <span>优化大文件处理的性能</span>
                            </li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <main class="container mx-auto max-w-5xl py-12 px-4">
        <!-- Introduction -->
        <section class="mb-16">
            <div class="prose max-w-none">
                <p class="text-lg text-gray-700 mb-6">在 <strong>Spring MVC</strong> 中，实现文件上传和下载的流程相对简单，但为了确保其高效性和安全性，开发过程中需要特别注意一些细节和最佳实践。</p>
            </div>
        </section>

        <!-- File Upload -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-8 flex items-center">
                <span class="bg-blue-100 text-blue-800 p-2 rounded-lg mr-4">
                    <i class="fas fa-upload"></i>
                </span>
                <span>文件上传实现</span>
            </h2>

            <!-- 1.1 MultipartResolver -->
            <div class="mb-10">
                <h3 class="text-2xl font-semibold mb-4 text-gray-800">1.1 配置 <code class="bg-gray-100 px-2 py-1 rounded">MultipartResolver</code></h3>
                <p class="mb-4">Spring MVC 通过 <code class="bg-gray-100 px-1 py-0.5 rounded">MultipartResolver</code> 处理文件上传，它负责将 HTTP 请求中的文件解析成 <code class="bg-gray-100 px-1 py-0.5 rounded">MultipartFile</code> 对象。</p>
                
                <div class="code-block mb-6">
                    <div class="code-header">
                        <span>XML 配置</span>
                        <span class="code-copy" onclick="copyCode(this)"><i class="far fa-copy mr-1"></i>复制</span>
                    </div>
                    <pre class="p-4 overflow-x-auto"><code>&lt;!-- 配置 CommonsMultipartResolver 或 StandardServletMultipartResolver --&gt;
&lt;bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"&gt;
  &lt;property name="maxUploadSize" value="5242880"/&gt; &lt;!-- 设置最大上传文件大小 --&gt;
&lt;/bean&gt;</code></pre>
                </div>
            </div>

            <!-- 1.2 Controller -->
            <div class="mb-10">
                <h3 class="text-2xl font-semibold mb-4 text-gray-800">1.2 Controller 文件上传逻辑</h3>
                <p class="mb-4">使用 <code class="bg-gray-100 px-1 py-0.5 rounded">MultipartFile</code> 接收上传的文件。</p>
                
                <div class="code-block mb-6">
                    <div class="code-header">
                        <span>Java 代码</span>
                        <span class="code-copy" onclick="copyCode(this)"><i class="far fa-copy mr-1"></i>复制</span>
                    </div>
                    <pre class="p-4 overflow-x-auto"><code>@Controller
public class FileUploadController {

    @PostMapping("/upload")
    public String handleFileUpload(@RequestParam("file") MultipartFile file, Model model) {
        if (!file.isEmpty()) {
            try {
                byte[] bytes = file.getBytes();
                Path path = Paths.get("upload-dir/" + file.getOriginalFilename());
                Files.write(path, bytes);

                model.addAttribute("message", "File uploaded successfully!");
            } catch (IOException e) {
                model.addAttribute("message", "File upload failed: " + e.getMessage());
            }
        } else {
            model.addAttribute("message", "File is empty.");
        }
        return "uploadResult";
    }
}</code></pre>
                </div>
            </div>

            <!-- 1.3 Notes -->
            <div class="mb-10">
                <h3 class="text-2xl font-semibold mb-4 text-gray-800">1.3 文件上传注意事项</h3>
                
                <div class="grid md:grid-cols-2 gap-6">
                    <!-- File Size -->
                    <div class="card bg-white p-6 hover-grow">
                        <div class="flex items-start mb-3">
                            <i class="fas fa-weight-hanging text-blue-500 mt-1 mr-3"></i>
                            <div>
                                <h4 class="font-semibold text-lg">文件大小限制</h4>
                                <p class="text-gray-600">应配置上传文件的大小限制</p>
                            </div>
                        </div>
                        <div class="code-block bg-gray-50">
                            <pre class="p-4 overflow-x-auto text-sm"><code>spring.servlet.multipart.max-file-size=5MB
spring.servlet.multipart.max-request-size=10MB</code></pre>
                        </div>
                    </div>
                    
                    <!-- File Type -->
                    <div class="card bg-white p-6 hover-grow">
                        <div class="flex items-start mb-3">
                            <i class="fas fa-file-alt text-purple-500 mt-1 mr-3"></i>
                            <div>
                                <h4 class="font-semibold text-lg">文件类型校验</h4>
                                <p class="text-gray-600">验证上传文件的 MIME 类型和扩展名</p>
                            </div>
                        </div>
                        <p class="text-gray-600">防止恶意文件上传（如 <code class="bg-gray-100 px-1 py-0.5 rounded">.exe</code> 文件）</p>
                    </div>
                    
                    <!-- Security -->
                    <div class="card bg-white p-6 hover-grow">
                        <div class="flex items-start mb-3">
                            <i class="fas fa-shield-alt text-green-500 mt-1 mr-3"></i>
                            <div>
                                <h4 class="font-semibold text-lg">安全性</h4>
                                <p class="text-gray-600">避免将上传文件直接存储在 Web 目录下</p>
                            </div>
                        </div>
                        <p class="text-gray-600">最好存储在非公开目录，或者使用数据库或云存储服务</p>
                    </div>
                    
                    <!-- Concurrency -->
                    <div class="card bg-white p-6 hover-grow">
                        <div class="flex items-start mb-3">
                            <i class="fas fa-tachometer-alt text-orange-500 mt-1 mr-3"></i>
                            <div>
                                <h4 class="font-semibold text-lg">并发控制</h4>
                                <p class="text-gray-600">高并发文件上传的处理</p>
                            </div>
                        </div>
                        <p class="text-gray-600">考虑磁盘 I/O 性能，必要时引入异步处理或消息队列</p>
                    </div>
                </div>
            </div>
        </section>

        <!-- File Download -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-8 flex items-center">
                <span class="bg-green-100 text-green-800 p-2 rounded-lg mr-4">
                    <i class="fas fa-download"></i>
                </span>
                <span>文件下载实现</span>
            </h2>

            <!-- 2.1 Controller -->
            <div class="mb-10">
                <h3 class="text-2xl font-semibold mb-4 text-gray-800">2.1 Controller 文件下载逻辑</h3>
                <p class="mb-4">通过 <code class="bg-gray-100 px-1 py-0.5 rounded">HttpServletResponse</code> 实现文件下载。首先设置响应头，然后将文件以流的形式传输给客户端。</p>
                
                <div class="code-block mb-6">
                    <div class="code-header">
                        <span>Java 代码</span>
                        <span class="code-copy" onclick="copyCode(this)"><i class="far fa-copy mr-1"></i>复制</span>
                    </div>
                    <pre class="p-4 overflow-x-auto"><code>@Controller
public class FileDownloadController {

    @GetMapping("/download/{filename:.+}")
    public void downloadFile(@PathVariable String filename, HttpServletResponse response) {
        Path filePath = Paths.get("upload-dir", filename);

        if (Files.exists(filePath)) {
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");

            try (InputStream inputStream = Files.newInputStream(filePath)) {
                FileCopyUtils.copy(inputStream, response.getOutputStream());
                response.flushBuffer();
            } catch (IOException e) {
                throw new RuntimeException("File download failed: " + e.getMessage());
            }
        } else {
            throw new FileNotFoundException("File not found");
        }
    }
}</code></pre>
                </div>
            </div>

            <!-- 2.2 Notes -->
            <div class="mb-10">
                <h3 class="text-2xl font-semibold mb-4 text-gray-800">2.2 文件下载注意事项</h3>
                
                <div class="grid md:grid-cols-3 gap-6">
                    <!-- Headers -->
                    <div class="card bg-white p-6 hover-grow">
                        <div class="flex items-start mb-3">
                            <i class="fas fa-heading text-indigo-500 mt-1 mr-3"></i>
                            <div>
                                <h4 class="font-semibold text-lg">响应头设置</h4>
                            </div>
                        </div>
                        <p class="text-gray-600"><code class="bg-gray-100 px-1 py-0.5 rounded">Content-Disposition</code> 设置为 <code class="bg-gray-100 px-1 py-0.5 rounded">attachment</code>，提示浏览器以附件形式下载文件，防止文件被直接显示或执行</p>
                    </div>
                    
                    <!-- Path Security -->
                    <div class="card bg-white p-6 hover-grow">
                        <div class="flex items-start mb-3">
                            <i class="fas fa-lock text-red-500 mt-1 mr-3"></i>
                            <div>
                                <h4 class="font-semibold text-lg">文件路径安全</h4>
                            </div>
                        </div>
                        <p class="text-gray-600">避免通过 URL 传递不安全的文件路径，最好通过固定目录或者使用加密的文件 ID 映射来获取文件</p>
                    </div>
                    
                    <!-- Large Files -->
                    <div class="card bg-white p-6 hover-grow">
                        <div class="flex items-start mb-3">
                            <i class="fas fa-server text-yellow-500 mt-1 mr-3"></i>
                            <div>
                                <h4 class="font-semibold text-lg">大文件处理</h4>
                            </div>
                        </div>
                        <p class="text-gray-600">对于大文件下载，应设置 <code class="bg-gray-100 px-1 py-0.5 rounded">response.flushBuffer()</code> 来避免内存溢出，并在服务器端使用流式处理避免将整个文件加载到内存</p>
                    </div>
                </div>
            </div>
        </section>

        <!-- Additional Considerations -->
        <section>
            <h2 class="text-3xl font-bold mb-8 flex items-center">
                <span class="bg-yellow-100 text-yellow-800 p-2 rounded-lg mr-4">
                    <i class="fas fa-exclamation-triangle"></i>
                </span>
                <span>注意事项</span>
            </h2>

            <div class="grid md:grid-cols-3 gap-6">
                <!-- Security Column -->
                <div>
                    <div class="flex items-center mb-4">
                        <i class="fas fa-shield-alt text-red-500 mr-3 text-xl"></i>
                        <h3 class="text-2xl font-semibold">安全性</h3>
                    </div>
                    
                    <div class="mb-6">
                        <div class="danger-box p-4 rounded-r-lg mb-4">
                            <h4 class="font-semibold mb-2">验证文件内容</h4>
                            <p>上传文件需要验证内容，防止通过上传合法扩展名文件隐藏恶意代码</p>
                        </div>
                        
                        <div class="danger-box p-4 rounded-r-lg">
                            <h4 class="font-semibold mb-2">路径注入攻击</h4>
                            <p>避免客户端直接提供文件路径，防止目录遍历攻击。建议使用 ID 或者哈希值映射到具体文件</p>
                        </div>
                    </div>
                </div>
                
                <!-- Performance Column -->
                <div>
                    <div class="flex items-center mb-4">
                        <i class="fas fa-tachometer-alt text-blue-500 mr-3 text-xl"></i>
                        <h3 class="text-2xl font-semibold">并发与性能</h3>
                    </div>
                    
                    <div class="mb-6">
                        <div class="tip-box p-4 rounded-r-lg mb-4">
                            <h4 class="font-semibold mb-2">异步处理</h4>
                            <p>对于大文件或并发上传下载场景，考虑使用异步请求或消息队列，避免阻塞主线程</p>
                        </div>
                        
                        <div class="tip-box p-4 rounded-r-lg">
                            <h4 class="font-semibold mb-2">限流与优化</h4>
                            <p>针对文件上传和下载的流量，可能需要通过 Nginx 或其他网关服务对传输速率进行限制，防止服务器资源被大量占用</p>
                        </div>
                    </div>
                </div>
                
                <!-- Storage Column -->
                <div>
                    <div class="flex items-center mb-4">
                        <i class="fas fa-database text-green-500 mr-3 text-xl"></i>
                        <h3 class="text-2xl font-semibold">文件存储</h3>
                    </div>
                    
                    <div class="mb-6">
                        <div class="warning-box p-4 rounded-r-lg mb-4">
                            <h4 class="font-semibold mb-2">存储位置</h4>
                            <p>将文件上传至专门的文件服务器、分布式文件系统或云存储（如 AWS S3），而不是应用服务器的本地磁盘</p>
                        </div>
                        
                        <div class="warning-box p-4 rounded-r-lg">
                            <h4 class="font-semibold mb-2">备份与冗余</h4>
                            <p>确保上传的文件存储机制具备备份与冗余能力，防止数据丢失</p>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </main>

    <!-- Visualization Section -->
    <section class="bg-gray-50 py-16">
        <div class="container mx-auto max-w-5xl px-4">
            <h2 class="text-3xl font-bold mb-12 text-center">文件上传下载流程可视化</h2>
            
            <div class="bg-white rounded-xl shadow-md p-6">
                <div class="mermaid">
                    graph TD
                        A[客户端] -->|上传请求| B(Spring MVC控制器)
                        B --> C{文件验证}
                        C -->|验证通过| D[存储文件]
                        C -->|验证失败| E[返回错误信息]
                        D --> F[返回成功响应]
                        
                        G[客户端] -->|下载请求| H(Spring MVC控制器)
                        H --> I{文件存在?}
                        I -->|是| J[设置响应头]
                        J --> K[流式传输文件]
                        I -->|否| L[返回404错误]
                </div>
            </div>
        </div>
    </section>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-8">
        <div class="container mx-auto max-w-5xl px-4">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="mb-4 md:mb-0">
                    <h3 class="text-xl font-semibold text-white mb-2">技术小馆</h3>
                    <a href="http://www.yuque.com/jtostring" class="hover:text-blue-300 transition-colors">http://www.yuque.com/jtostring</a>
                </div>
                <div class="flex space-x-4">
                    <a href="#" class="hover:text-white transition-colors"><i class="fab fa-github text-xl"></i></a>
                    <a href="#" class="hover:text-white transition-colors"><i class="fab fa-twitter text-xl"></i></a>
                    <a href="#" class="hover:text-white transition-colors"><i class="fab fa-linkedin text-xl"></i></a>
                </div>
            </div>
        </div>
    </footer>

    <script>
        // Initialize Mermaid
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: false,
                htmlLabels: true,
                curve: 'basis'
            }
        });

        // Copy code functionality
        function copyCode(element) {
            const codeBlock = element.closest('.code-block').querySelector('pre code');
            const codeText = codeBlock.textContent;
            
            navigator.clipboard.writeText(codeText).then(() => {
                const originalText = element.innerHTML;
                element.innerHTML = '<i class="fas fa-check mr-1"></i>已复制';
                
                setTimeout(() => {
                    element.innerHTML = originalText;
                }, 2000);
            });
        }
    </script>
</body>
</html>
```